package coderead.maven.service;
/**
 * @Copyright 源码阅读网 http://coderead.cn
 */

/**
 * @author 鲁班大叔
 * @date 2021
 */

import coderead.maven.bean.ArtifactIndexInfo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 用于记录版本使用数据
 */
@Slf4j
@Component
//@DependsOn("indexShortSearch")
public class ArtifactInfoStore implements InitializingBean {

    @Getter
    @Setter
    @Value("${versionStoreFile}")
    String versionStoreFile;

    @Getter
    @Setter
    @Value("${index.repository.shortIndexFile}")
    String indexFile;

    // 版本下载统计
    private final Map<String, AtomicInteger> versionCounts = new ConcurrentHashMap<>();
    private Map<String, ArtifactIndexInfo> infos;


    public void versionCount(String groupId, String artifactId, String versionId) {
        String key = groupId + ":" + artifactId + ":" + versionId;
        if (versionCounts.containsKey(key)) {
            AtomicInteger integer = versionCounts.get(key);
            if (integer != null) {
                integer.incrementAndGet();
            }
        } else {
            versionCounts.computeIfAbsent(key, k -> new AtomicInteger(1));
        }
    }

    public void storeVersionCount() throws IOException {
        BufferedWriter writer = new BufferedWriter(new FileWriter(versionStoreFile));
        PrintWriter printWriter = new PrintWriter(writer);
        versionCounts.entrySet().stream().map((e) -> e.getKey() + " " + e.getValue()).forEach(printWriter::println);
        printWriter.flush();
        printWriter.close();
        // 更新到索引中
        putToArtifactIndexInfo();
    }

    //  保存Artifact信息到索引文件中
    public void storeArtifact() throws IOException {
        BufferedWriter writer = new BufferedWriter(new FileWriter(indexFile));
        PrintWriter printWriter = new PrintWriter(writer);
        getAllArtifact(false).stream()
                             .map(ArtifactIndexInfo::toLine)
                             .forEach(printWriter::println);
        printWriter.flush();
        printWriter.close();
    }


    public ArtifactIndexInfo findArtifact(String groupId, String artifactId) {
        return infos.get(groupId + " " + artifactId);
    }


    // 合并之后覆盖原来的 Artifact 数据
    public void margeAndCoverArtifact(List<ArtifactIndexInfo> newArtifacts) {
        // 版本更新
        Map<String, ArtifactIndexInfo> newInfos = new HashMap<>();
        String key;
        ArtifactIndexInfo oldArtifact;
        for (ArtifactIndexInfo artifact : newArtifacts) {
            key = artifact.groupId + " " + artifact.artifactId;
            newInfos.put(key, artifact);
            if (infos.containsKey(key)) {
                oldArtifact = infos.get(key);
                artifact.indexClass = oldArtifact.indexClass;
                if (artifact.lastModified > oldArtifact.lastModified) {
                    // 新版本 重新索引类
                    artifact.indexClass = false;
                }
            }
        }
        this.infos = newInfos;
        // 更新使用次数
        putToArtifactIndexInfo();
        try {
            storeArtifact();
        } catch (IOException e) {
            log.error("索引保存失败：", e);
        }
    }


    private void putToArtifactIndexInfo() {
        Map<String, Integer> map = versionCounts.entrySet().stream()
                                                .collect(Collectors.
                                                        toMap(e -> e.getKey().substring(0, e.getKey().lastIndexOf(":")),
                                                                e -> e.getValue().intValue(),
                                                                Integer::sum));
        map.forEach((k, v) -> {
            String[] split = k.split(":");
            ArtifactIndexInfo indexInfo = infos.get(split[0] + " " + split[1]);
            if (indexInfo != null) {
                indexInfo.setHot(v);
            }
        });
    }


    public void loadVersionCount() throws IOException {
        versionCounts.clear();
        try (Stream<String> lines = Files.lines(new File(versionStoreFile).toPath())) {
            lines.map(line -> {
                     String[] s = line.split(" ");
                     if (s.length != 2) {
                         log.error("版本引用次数格式错误: {}", line);
                         return null;
                     }
                     return s;
                 }).filter(Objects::nonNull)
                 .forEach(a -> versionCounts.put(a[0], new AtomicInteger(Integer.parseInt(a[1]))));

        }

        putToArtifactIndexInfo();
    }

    public void loadArtifacts() throws IOException {
        if (infos != null) {
            infos.clear();
            infos = null;
        }

        log.info("开始索引解析加载：{}", indexFile);
        File file = new File(indexFile);
        Assert.isTrue(file.exists(), "找不到索引文件：" + indexFile);
        try (Stream<String> lines = Files.lines(file.toPath())) {
            this.infos = lines.filter(StringUtils::hasText)
                              .map(line -> {
                                  try {
                                      return ArtifactIndexInfo.parse(line);
                                  } catch (IllegalArgumentException e) {
                                      log.error(e.getMessage(), e);
                                  }
                                  return null;
                              }).filter(Objects::nonNull)
                              .collect(Collectors.toMap(a -> a.groupId + " " + a.artifactId, a -> a));
            log.info("完成索引加载：{}", indexFile);
        }

    }


    public int getVersionCount(String groupId, String artifactId, String versionId) {
        String key = groupId + ":" + artifactId + ":" + versionId;
        return versionCounts.getOrDefault(key, new AtomicInteger(0)).intValue();
    }


    public List<ArtifactIndexInfo> getAllArtifact(boolean sort) {
        Collection<ArtifactIndexInfo> values = infos.values();
        if (sort) {
            return values.stream().sorted((Comparator.comparingInt(o -> o.getArtifactId().length()))).collect(Collectors.toList());
        }
        return new ArrayList<>(values);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        for (String s : Arrays.asList(versionStoreFile, indexFile)) {
            File file = new File(s);
            if (file.exists()) {
                continue;
            }

            File parentFile = file.getParentFile();
            if (!parentFile.exists()) {
                boolean mkdir = parentFile.mkdirs();
                if (!mkdir) {
                    log.warn("创建目录失败：{}", file.getParentFile());
                }
            }

            boolean newFile = file.createNewFile();
            if (!newFile) {
                log.warn("创建文件失败：{}", file.getAbsoluteFile());
            }
        }

        // 加载 Artifact 数据
        loadArtifacts();
        // 加载版本数据
        loadVersionCount();
    }

}
